import "dart:io";
import "dart:typed_data";
import "dart:ui" as ui;
import "package:flutter/material.dart";
import "dart:async";

typedef AsyncImageWidgetBuilder<T> = Widget Function(
    BuildContext context, AsyncSnapshot<T> sanpshot, String url);

typedef AsyncImageFileWidgetBuilder<T> = Widget Function(
    BuildContext context, AsyncSnapshot<T> sanpshot, File file);

typedef AsyncImageMemoryWidgetBuilder<T> = Widget Function(
    BuildContext context, AsyncSnapshot<T> sanpshot, Uint8List bytes);

enum AsperctRaioImageType { NETWORL, FILE, ASSET, MEMORY }

class AsperctRaioImage extends StatelessWidget {
  late final String url;
  late final File file;
  late final Uint8List bytes;
  final ImageProvider provider;
  late final AsperctRaioImageType type;
  late final AsyncImageWidgetBuilder<ui.Image> builder;
  late final AsyncImageFileWidgetBuilder<ui.Image> fileBuilder;
  late final AsyncImageMemoryWidgetBuilder<ui.Image> memoryBuilder;

  // 网络图片
  AsperctRaioImage.network(this.url, {super.key, required this.builder})
      : provider = NetworkImage(url),
        type = AsperctRaioImageType.NETWORL;

  // 文件图片
  AsperctRaioImage.file(this.file, {super.key, required this.fileBuilder})
      : provider = FileImage(file),
        type = AsperctRaioImageType.FILE;

  // 本地图片
  AsperctRaioImage.asset(this.url, {super.key, required this.builder})
      : provider = AssetImage(url),
        type = AsperctRaioImageType.ASSET;

  AsperctRaioImage.memory(this.bytes, {super.key, required this.memoryBuilder})
      : provider = MemoryImage(bytes),
        type = AsperctRaioImageType.MEMORY;

  @override
  Widget build(BuildContext context) {
    final ImageConfiguration config = createLocalImageConfiguration(context);
    final Completer<ui.Image> completer = Completer<ui.Image>();
    final ImageStream stream = provider.resolve(config);
    late ImageStreamListener listener;
    listener = ImageStreamListener(
      (ImageInfo image, bool synchronousCall) {
        completer.complete(image.image);
        stream.removeListener(listener);
      },
      onError: (Object exception, StackTrace? stackTrace) {
        // ignore: null_argument_to_non_null_type
        completer.complete();
        stream.removeListener(listener);
        FlutterError.reportError(
          FlutterErrorDetails(
            context: ErrorDescription('image filed to precache'),
            library: 'image resource service',
            exception: exception,
            stack: stackTrace,
            silent: true,
          ),
        );
      },
    );
    stream.addListener(listener);

    return FutureBuilder(
        future: completer.future,
        builder: (BuildContext context, AsyncSnapshot<ui.Image> snapshot) {
          if (snapshot.hasData) {
            if (type == AsperctRaioImageType.FILE) {
              return fileBuilder(context, snapshot, file);
            } else if (type == AsperctRaioImageType.MEMORY) {
              return memoryBuilder(context, snapshot, bytes);
            } else {
              return builder(context, snapshot, url);
            }
          } else {
            return Container();
          }
        });
  }
}
